题目链接:┏ (゜ω゜)=☞ 走起

题目大意

n 个城市 m 条路,每个城市都有救援小组,所有的边的边权已知。给定起点和终点,求从起点到终点的最短路径条数以及最短路径上的救援小组数目之和。如果有多条就输出点权(城市救援小组数目)最大的那个~

分析

用一遍 Dijkstra 算法,救援小组个数相当于点权,用 Dijkstra 求边权最小的最短路径的条数,以及这些最短路径中点权最大的值,d[i] 表示从出发点到 i 结点最短路径的路径长度,num[i] 表示从出发点到 i 结点最短路径的条数,team[i] 表示从出发点到 i 点救援队的数目之和,分最短路 < 和 = 两种情况更新数据。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include<bits/stdc++.h>
using namespace std;

const int N = 510, INF = 0x3f3f3f3f;
int g[N][N]; //存储边
int d[N], team[N], w[N], num[N]; // w 存储每个点的救援队数量
bool st[N];

int main() {
int m, n, c1, c2;
scanf("%d%d%d%d", &m, &n, &c1, &c2);
for(int i = 0; i < m; i++) scanf("%d", &w[i]);

//初始化
memset(g, 0x3f, sizeof g);
memset(d, 0x3f, sizeof d);
int a, b, c;
for(int i = 0; i < n; i++) {
scanf("%d%d%d", &a, &b, &c);
g[a][b] = g[b][a] = c;
}
d[c1] = 0;
num[c1] = 1;
team[c1] = w[c1];

for(int j = 0; j < n; j++) {
int t = -1;
for(int i = 0; i < n; i++) //在还未确定最短距离的点中,寻找距离最小的点
if(!st[i] && (t == -1 || d[t] > d[i]))
t = i;

st[t] = true;

for(int i = 0; i < n; i++) { //用 t 更新其他其他点的距离
if(!st[i] && g[t][i] != INF) {
if(d[t] + g[t][i] < d[i]) {
d[i] = d[t] + g[t][i];
num[i] = num[t]; //更新到 i 点的最短路数量为 num[t] * 1
team[i] = team[t] + w[i]; //更新 i 点救援队数量为 t 点数量 + i 点数量
} else if(d[t] + g[t][i] == d[i]) {
num[i] += num[t]; //距离相等,所以数量需要相加
team[i] = max(team[i], team[t] + w[i]); //救援队数量取大的
}
}
}
}
printf("%d %d", num[c2], team[c2]);
return 0;
}